home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1990, 1991 Stanford University
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that (i) the above copyright notices and this permission notice appear in
- * all copies of the software and related documentation, and (ii) the name
- * Stanford may not be used in any advertising or publicity relating to
- * the software without the specific, prior written permission of
- * Stanford.
- *
- * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
- * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
- *
- * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
- * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
- /* $Header: /Source/Media/collab/DTR/RCS/audio.c,v 1.10 92/01/09 12:39:45 drapeau Exp Locker: derek $ */
- /* $Log: audio.c,v $
- * Revision 1.10 92/01/09 12:39:45 drapeau
- * Slight modifications to the code to make it ANSI-compliant.
- *
- * Revision 1.0 92/01/06 17:37:18 drapeau
- * Cosmetic changes to make code easier to read and to conform to
- * programming specifications.
- *
- * Revision 0.25 91/09/18 22:46:22 derek
- * The following things are done:
- * 1. The Makefile is changed corresponding to the changes in collab/.
- * 2. Copyright messages included.
- * 3. Some minor bugs fixed.
- *
- * Revision 0.24 91/08/21 11:28:41 derek
- * The following changes are made:
- * 1. Now the duration and size of the recorded sound will be displayed
- * during recording.
- * 2. I have changed GetSelection() corresponding to the request of Tek joo
- * 3. Info Panel is added to the application.
- * 4. Fixed SizeToFitHandler() so that when no file or buffer is currently
- * loaded, it would not do anything (except giving a warning
- * notice_prompt).
- * 5. Inplemented the `Close' Menu option in the document menu.
- * 6. Fixed the bug in which after ClearAll and I press PreviewEdit,
- * the edit wont be played.
- * 7. I have made the changes corresponding to the change in OpenPanel's
- * name. (from OpenPanel to Browse).
- * 8. Incorporated BrowseCheck to check command line arg.
- * 9. Changed most EditingStatusMessages to NoticePrompts.
- * 10. SoundFileSaveAsPopUp and EditListSaveAsPopUp are removed
- * from the application.
- *
- * Revision 0.23 91/08/14 16:13:29 derek
- * Fixed a few saving/appending bugs.
- *
- * Revision 0.22 91/08/13 20:35:28 derek
- * The buttons (play, pause, record) will now flash after they are pressed.
- * This only applies to times when audio files (not edit-lists) are
- * played.
- *
- * Revision 0.21 91/08/08 10:59:53 derek
- * This is a cleaner version. I have removed lots of printf/fprintf
- * statements from it, and have also cleaned up the code using xsaber.
- * This version should run substantially faster.
- *
- * Revision 0.20 91/08/07 16:22:40 derek
- * The Edit list part of DTR is done. OpenPanel is also incorporated.
- *
- * Revision 0.19 91/08/06 12:40:25 derek
- * Edit list panel is done. Still need to link it to the network code.
- *
- * Revision 0.18 91/07/31 14:49:27 derek
- * I have changed the user interface so that text fields like size and
- * duration will be displayed in normal (not bold) format. I also fixed
- * a network bug. In addition, I have added a routine to check how
- * much disk space is left in /usr/tmp.
- *
- * Revision 0.17 91/07/29 15:09:33 derek
- * The playing w/o stopping error is fixed.
- *
- * Revision 0.16 91/07/27 11:44:43 derek
- * I have added audio output options to the application. User can choose
- * either headphone or speaker as output device.
- *
- * Revision 0.15 91/07/24 12:50:08 derek
- * Disk editing is done. Now the application can record sound infinitely,
- * as long as there is disk space available. Command line args are also
- * supported.
- *
- * Revision 0.14 91/07/23 21:16:57 derek
- * This version is not ready for release. Disk space editing is half-done:
- * the application can play an infinite sound and the canvases can handle
- * infinite sound files. The app is pretty bug free too, I think. The
- * weakness is that it cannot record sound infinitely.
- *
- * Revision 0.13 91/06/26 15:54:26 derek
- * I have reformatted the code to conform coding specs.
- *
- * Revision 0.12 91/06/20 19:53:53 derek
- * The network part should be working. Also fixed numerous minor parts
- * involving the canvas and the display.
- *
- * Revision 0.10 1991/04/25 01:42:30 derek
- * This version is checked in on 4/24/91
- * */
- static char rcsid[] = "$Header: /Source/Media/collab/DTR/RCS/audio.c,v 1.10 92/01/09 12:39:45 drapeau Exp Locker: derek $";
-
- #include "dtr.h"
- #include "dtr_ui.h"
-
- void
- InitAudio()
- {
- extern dtr_mainWindow_objects *dtr_mainWindow;
-
- EVENT("Init_Audio");
-
- Audioctl_fd = -1;
- Audio_fd = -1;
- Sync_sched = FALSE;
-
- xv_set(dtr_mainWindow->playGain,
- PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
- xv_set(dtr_mainWindow->recordGain,
- PANEL_NOTIFY_LEVEL, PANEL_ALL, NULL);
- }
-
-
- /*
- * Open audio control device (/dev/audioctl) and read its state.
- * This may be used for state get/set (eg, volume levels) without holding
- * the main audio device (/dev/audio) open.
- */
- void
- InitAudioControl()
- {
- EVENT("Init_Audio_Control");
- if ((Audioctl_fd = open(AUDIO_CTLDEV, O_RDWR)) < 0) /* Open audio control device */
- {
- PERROR(AUDIO_CTLDEV); /* If audioctl device cannot be opened, ... */
- Device_phdr.sample_rate = 8000; /* ... initialize the audio header to default ... */
- Device_phdr.channels = 1; /* ... value. */
- Device_phdr.bytes_per_unit = 1;
- Device_phdr.samples_per_unit = 1;
- Device_phdr.encoding = AUDIO_ENCODING_ULAW;
- Device_rhdr = Device_phdr;
- Buffer.hdr = Device_phdr;
- }
- else
- {
- if (ioctl(Audioctl_fd, I_SETSIG, S_MSG) < 0) /* Tell the driver to send SIGPOLL on device ... */
- PERROR("Could not issue I_SETSIG ioctl"); /* ... state changes. */
-
- if ((audio_get_play_config(Audioctl_fd, &Device_phdr) != /* Get the device play and record ... */
- AUDIO_SUCCESS) || /* ... configuration ie. get the current ... */
- (audio_get_record_config(Audioctl_fd, &Device_rhdr) != /* ... status of the device. */
- AUDIO_SUCCESS))
- {
- PERROR("Could not get encoding configuration");
- }
- }
- AUDIO_INITINFO(&Audio_state);
- } /* end function InitAudioControl */
-
-
- /*
- * Open the audio device, using the Active_flag to derive open modes.
- * Returns:
- * 0 Successful open
- * 1 Audio device is busy (try again later)
- * -1 Error during open
- */
- int
- AudioOpen(flag)
- int flag;
- {
- EVENT("Audio_Open");
-
- if (Audio_fd >= 0)
- { /* already open. */
- fprintf(stderr, "%s already open\n", AUDIO_DEV);
- return (-1);
- }
-
- flag = ((flag & RECORD) ? O_RDONLY : O_WRONLY) | O_NDELAY; /* Read-only access if Record. Write-only if ... */
- /* ... Play or Alert. */
- if ((Audio_fd = open(AUDIO_DEV, flag)) < 0)
- {
- if ((errno == EINTR) || (errno == EBUSY))
- return (1);
- PERROR(AUDIO_DEV);
- return (-1);
- }
-
- flag = fcntl(Audio_fd, F_GETFL, 0) | FNDELAY; /* Set up for asynchronous, non-blocking i/o. */
- if (fcntl(Audio_fd, F_SETFL, flag) < 0)
- PERROR("F_SETFL fcntl");
- if (ioctl(Audio_fd, I_SETSIG, S_INPUT|S_OUTPUT|S_MSG) < 0)
- PERROR("I_SETSIG ioctl");
- return (0);
- }
-
-
- /*
- * Convert local gain into device parameters
- */
- double
- ScaleGain(g)
- int g;
- {
- return((double)g/(double)MAX_GAIN);
- }
-
-
- /*
- * Convert device gain into the local scaling factor
- */
- int
- UnscaleGain(g)
- double g;
- {
- return (irint((double)MAX_GAIN * g));
- }
-
- /*
- * Read the audio device state and translate fields into
- * values we understand.
- */
- BOOL
- AudioReadState(aip)
- Audio_info *aip;
- {
- extern dtr_mainWindow_objects *dtr_mainWindow;
-
- EVENT("Audio_Read_State");
- if ((Audioctl_fd > 0) &&
- (audio_getinfo(Audioctl_fd, aip) != AUDIO_SUCCESS))
- { /* If error, quit trying to access control device. */
- Audioctl_fd = -1;
- AlertByNoticePrompt(dtr_mainWindow->menuControlPanel,
- "Error: audio control device error.");
- }
-
- if (Audioctl_fd < 0)
- { /* Set dummy values. */
- aip->play.gain = 35;
- aip->record.gain = 60;
- aip->play.port = 0;
- aip->play.eof = 0;
- aip->play.error = FALSE;
- aip->play.pause = FALSE;
- aip->record.error = FALSE;
- aip->record.pause = FALSE;
- return (FALSE);
- }
-
- aip->play.gain = UnscaleGain((double)(aip->play.gain - /* Convert to values that we understand. */
- AUDIO_MIN_GAIN) /
- (double)AUDIO_MAX_GAIN);
- aip->record.gain =
- UnscaleGain((double)(aip->record.gain - AUDIO_MIN_GAIN) /
- (double)AUDIO_MAX_GAIN);
-
- aip->play.port = (unsigned) ((aip->play.port == AUDIO_SPEAKER) ? 0 : 1);
- return (TRUE);
- }
-
-
- void
- AudioUpdatePanel(init)
- int init;
- {
- Audio_info Audio_new;
-
- EVENT("Audio_Update_Panel");
-
- if (!AudioReadState(&Audio_new) && !init)
- return;
-
- if (ActiveFlag & PLAY)
- Buffer.paused = Audio_new.play.pause;
- if (ActiveFlag & RECORD)
- Buffer.paused = Audio_new.record.pause;
-
- if (!ActiveFlag) /* if not active, assume pause state only if... */
- { /* ...both flags set. */
- Buffer.paused = Audio_new.play.pause && Audio_new.record.pause;
- }
- else if (ActiveFlag & PLAY)
- {
- if (Buffer.paused) /* put in timer and screen update routines. */
- {
- CancelVUMeterTimer();
- /* CancelButtonGlowTimer();*/
- }
- else
- {
- SetVUMeterTimer((double)SCOPE_WIDTH/(double)Buffer.hdr.sample_rate);
- /* SetButtonGlowTimer(GLOW_INTERVAL);*/
- }
- }
- Audio_new.play.pause = Buffer.paused;
- Audio_state = Audio_new;
- } /* end function AudioUpdatePanel */
-
-
- Notify_value
- SigpollAsyncHandler(client, sig, when)
- Notify_client client;
- int sig;
- Notify_signal_mode when;
- {
- int save_errno;
-
- EVENT("Sigpoll_Async_Handler");
-
- save_errno = errno;
-
- if (!WaitFlag)
- { /* Device is open. Attempt to keep queues filled. */
- if (ActiveFlag & PLAY)
- PlayService();
- if (ActiveFlag & RECORD)
- {
- RecordService();
- }
- }
-
- if (!Sync_sched) /* SIGPOLL is also sent if the state of the... */
- { /* ...device is changed. Schedule the... */
- Sync_sched = TRUE; /* ...synchronous handler, unless it was... */
- (void) notify_post_event(SIGPOLL, NULL, NOTIFY_SAFE); /* ...already scheduled. */
- }
-
- errno = save_errno;
-
- UpdateRecordingMessageDisplay();
-
- return (NOTIFY_DONE);
- }
-
-
- /*
- * Synchronous SIGPOLL handler...entered when the asynchronous SIGPOLL
- * handler detects something to do synchronously, like updating displays.
- */
- Notify_value
- SigpollSyncHandler(client, event, arg, when)
- Notify_client client;
- Notify_event event;
- Notify_arg arg;
- Notify_event_type when;
- {
- EVENT("Sigpoll_Sync_Handler");
-
- Sync_sched = FALSE; /* flag to async handler. */
-
- /* Waiting for the device open to succeed */
- if (WaitFlag)
- {
- if (!AudioOpen(WaitFlag))
- { /* device is open...start transfers. */
- if (WaitFlag & PLAY)
- {
- WaitFlag &= ~PLAY;
- StartPlay();
- }
- if (WaitFlag & RECORD)
- {
- WaitFlag &= ~RECORD;
- StartRecord();
- }
- }
- }
-
- AudioUpdatePanel(FALSE);
-
- if ((ActiveFlag & PLAY) && Audio_state.play.eof && /* Detect whether output is complete. The... */
- Buffer.draining) /* ...play.eof flag is incremented when a... */
- { /* ...zero-length write has been processed. */
- StopPlay(); /* Output draining is complete. */
-
- #ifdef notdef
- if (Audio_state.play.error)
- {
- AlertByNoticePrompt(dtr_mainWindow->menuControlPanel,
- "Underflow detected during Play.");
- }
- #endif
- }
- return (NOTIFY_DONE);
- }
-
-
- /*
- * Flush queued output and close the audio device.
- */
- void
- AudioFlushClose()
- {
- EVENT("Audio_Flush_Close");
-
- if (Audio_fd < 0)
- return;
- (void) audio_flush(Audio_fd);
- (void) close(Audio_fd);
- Audio_fd = -1;
- }
-
-
- void
- SetPlayGain(volume)
- int volume;
- {
- extern dtr_mainWindow_objects *dtr_mainWindow;
- double gain;
-
- xv_set(dtr_mainWindow->playGain, PANEL_VALUE, volume, NULL);
- gain = ScaleGain(volume);
- Audio_state.play.gain = ~0;
- (void) audio_set_play_gain(Audioctl_fd, &gain);
- }
-
-